<?php

namespace app\uniapp\service;

use app\common\exception\MiException;
use app\model\store\Coupon;
use app\model\store\UserCoupon;
use app\uniapp\service\traits\InstanceTrait;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\db\Query;

class UserCouponService extends UniBaseService
{

    use InstanceTrait;

    private int $couponStatusWhere = 0;

    /**
     * 优惠券状态条件
     * 1-未使用（未过期且未使用） 2-已使用 3-已过期（已过期且未使用）
     * @param int $status
     * @return UserCouponService
     */
    public function setCouponStatusWhere(int $status): static
    {
        $this->couponStatusWhere = $status;
        return $this;
    }

    function initialize()
    {
        $this->model = new UserCoupon();
    }

    function formatData(array $data): array
    {
        return $data;
    }


    public function query(): Query
    {
        if ($this->couponStatusWhere){
            $where = [];
            // 有效期包含截止日期，所以当前时间戳减去24小时
            $time = time() - 24*60*60;
            if ($this->couponStatusWhere == 1){    // 未使用
                // 未使用且未过期
                $where[] = ['end_date', '>', $time];
                $where[] = ['is_has_use', '=', 0];
            }elseif ($this->couponStatusWhere == 2) {  // 已使用
                $where[] = ['is_has_use', '=', 1];
            }elseif ($this->couponStatusWhere == 3){   // 已过期
                // 未使用且过期
                $where[] = ['is_has_use', '=', 0];
                $where[] = ['end_date', '<', $time];
            }

            $this->where = array_merge($this->where, $where);
        }

        return $this->makeQuery()->filter(function ($v) {
            //
            // 1-未使用 2-已使用 3-已过期
            $time = time() - 24*60*60;
            if ($v->is_has_use == 1){   // 如果已使用，不论是否过期，都属于已使用
                $status = 2;
            }else{
                if ($v->end_date > $time){     // 没有过期
                    $status = 1;
                }else{  // 过期
                    $status = 3;
                }
            }
            $v->couponStatus = $status;
            $v->validDate = [date('Y.m.d', $v->start_date),date('Y.m.d', $v->end_date)]; // 有效期
            $v->applyGoodsIdArr = miExplode($v->apply_goods_ids);
        });
    }


    /**
     * 根据平台优惠券id，创建我的优惠券
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws MiException
     * @throws ModelNotFoundException
     */
    public function createByCouponId(int $couponId, int $userId){
        if (!$userId){
            throw new MiException("缺少用户ID");
        }
        $info = Coupon::find($couponId);
        if (!$info){
            throw new MiException("优惠券不存在");
        }
        // 计算优惠券的有效期
        if ($info->expire_type == 1){   // 领取后生效
            // 使用凌晨时间计算，不使用当前时间，如2023-09-26 12:43:23，转成2023-09-26 00:00:00再计算
            $startDate = strtotime( date('Ymd') );
            $endDate = $startDate +  $info->expire_day * 24 * 60 * 60;
        }else{  // 固定日期
            $startDate = $info->start_date;
            $endDate = $info->end_date;
        }
        // 创建我的优惠券
        $coupon = UserCouponService::instance()->create([
            'coupon_id' => $info->id,
            'user_id' => $userId,
            'title' => $info->title,
            'discount_type' => $info->discount_type,
            'discount_price' => $info->discount_price,
            'discount_rate' => $info->discount_rate,
            'min_price' => $info->min_price,
            'expire_type' => $info->expire_type,
            'start_date' => $startDate,
            'end_date' => $endDate,
            'apply_type' => $info->apply_type,
            'apply_goods_ids' => $info->apply_goods_ids,
        ]);

        // 优惠券数量减1（不限数量的不减），已领取数量+1
        $info->get_num = $info->get_num + 1;
        if($info->total_num!=-1){
            $info->total_num = $info->total_num-1;
        }
        $info->save();
    }


    /**
     * 计算订单的优惠券折扣
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws MiException
     */
    public function computeOrderCouponPrice(array $order): array
    {
        if(!$order['isUseCoupon']){ // 用户选择不使用优惠券，原样返回
            return $order;
        }

        $couponId = $order['user_coupon_id'];    // 用户选择的优惠券
        // 当前订单可用的所有优惠券
        $coupons = $order['coupons'];
        if ($couponId){   // 用户选择的优惠券
            // 从可用券列表中获取券信息
            $tCoupons = $coupons->where('id', $couponId);
            $coupon = count($tCoupons) ? $tCoupons[0]:null;
            if (!$coupon){
                throw new MiException("优惠券无效");
            }

        }else{  // 用户没有选择优惠券，自动选择一张【未使用】的优惠券
            $coupon = count($coupons) ? $coupons[0] : null;
        }

        $order['coupon'] = $coupon;
        if (!$coupon){  // 无可用优惠券，直接返回
            return  $order;
        }

        $order['coupon_id'] = $coupon->id;
        $applyInfo = [
            'items' => [],
            'total_price' => 0,
        ];
        foreach ($order['items'] as $itemKey => $it){
            if ($coupon->apply_type == 1){
                // 所有商品可用
                $applyInfo['items'][$itemKey] = $it;
                $applyInfo['total_price'] += $it['pay_price'];
            }elseif ($coupon->apply_type == 2){ // 指定商品
                if (in_array($it['goods_id'], $coupon->applyGoodsIdArr)) {
                    $applyInfo['items'][$itemKey] = $it;
                    $applyInfo['total_price'] += $it['pay_price'];
                }
            }elseif ($coupon->apply_type == 3){ // 排除商品
                if (!in_array($it['goods_id'], $coupon->applyGoodsIdArr)) {
                    $applyInfo['items'][$itemKey] = $it;
                    $applyInfo['total_price'] += $it['pay_price'];
                }
            }
        }
        // 计算抵扣金额
        if ($coupon->discount_type == 1){   // 满减券
            $couponPrice = $coupon->discount_price;
        }else{  // 折扣券
            // 计算折扣金额时不做四舍五入，保留两位小数，直接舍弃多余的小数
            $couponPrice = $applyInfo['total_price'] * $coupon->discount_rate/100;
            $couponPrice = floor($couponPrice * 100) / 100;
        }
        // 抵扣金额大于等于订单金额时，将订单金额赋值给抵扣金额
        $couponPrice = ($couponPrice >= $applyInfo['total_price']) ? $applyInfo['total_price'] : $couponPrice;
        // 将优惠券抵扣的金额平均分配到每个商品
        foreach ($applyInfo['items'] as $k => $aIt){
            // 计算出当前商品的总价格占总抵扣金额的比例
            $itemRate = $aIt['pay_price']/$applyInfo['total_price'];
            // 计算抵扣金额，向下取整，直接舍弃小数后两位后的所有数字
            $aIt['coupon_price'] = floor($itemRate*$couponPrice*100)/100;
            $aIt['pay_price'] = floor($aIt['pay_price']*100 - $aIt['coupon_price']*100) / 100;
            $order['items'][$k] = $aIt;
        }
        // 重新计算订单支付金额
        $payPrice = 0;
        foreach ($order['items'] as $item){
            $payPrice += $item['pay_price'];
        }
        $order['pay_price'] = floor($payPrice*100)/100;
        $order['coupon_price'] = $couponPrice;
        return $order;
    }


    /**
     * 获取指定订单可用的所有优惠券
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function getOrderCoupons(array $order): \think\Collection|array
    {
        $coupons = $this->setCouponStatusWhere(1)->setWhere([
            ['user_id', '=', $this->userId],
            ['min_price', '<=', $order['total_price']],
        ])->setOrder('discount_price desc')->select();
        // 京东方a
        $goodsIds = []; // 订单商品id
        foreach ($order['items'] as $v){
            $goodsIds[] = $v['goods_id'];
        }

        return $coupons->filter(function ($v) use($goodsIds) {
            if ($v->apply_type == 1){
                return true;
            }elseif ($v->apply_type == 2){  // 指定商品可用
                $arr = array_intersect($v->arrayGoodsIdArr, $goodsIds);
                // 数组不为空，可用
                return count($arr)>0;
            }elseif ($v->apply_type == 3){  // 排除商品
                $arr = array_intersect($v->arrayGoodsIdArr, $goodsIds);
                // 包含排除商品，但不全都是排除商品，可用
                return count($arr) != count($goodsIds);
            }
        });
    }

}
